from sqlalchemy import or_, text, exc
from sqlalchemy.ext.declarative import declarative_base
from fastapi import HTTPException


Base = declarative_base()


class Crud(Base):

    __abstract__ = True
    Keyword = ()

    @classmethod
    def keyword_query(cls, query, q):
        """关键词搜索"""
        if q and cls.KeyWord:
            return query.filter(or_(*[getattr(cls, field).like(f'{q}%') for field in cls.KeyWord]))
        return query

    @classmethod
    def get_item(cls, session, filter_: list, error=True):
        """获取单条数据"""
        item = session.query(cls).filter(*filter_).first()
        if not item and error:
            raise HTTPException(status_code=404, detail='数据不存在')
        return item

    @classmethod
    def create_item(cls, session, body, commit=True):
        """创建单条数据"""
        try:
            item = cls(**body)
            session.add(item)
            session.flush()
            if commit:
                session.commit()
        except exc.IntegrityError as e:
            raise HTTPException(status_code=400, detail='数据已存在')
        except Exception as e:
            raise HTTPException(status_code=400, detail='数据添加失败')
        return item
    
    @classmethod
    def create_items(cls, session, datas, verify=False):
        """创建多条数据"""
        datas = [cls(**data) for data in datas]
        session.add_all(datas)
        session.commit()
        return []
        
    @classmethod
    def update_item(cls, session, filter_: list = None, update: dict = None, commit=True):
        """修改单条数据"""
        item = cls.get_item(session, filter_=filter_)
        if not item:
            raise HTTPException(status_code=404, detail='数据不存在')

        for k, v in update.items():
            if getattr(item, k) == v:
                continue
            setattr(item, k, v)
        if commit:
            session.commit()
        return item

    # 批量操作
    @classmethod
    def get_items(cls,  session, q: str = None, filter_: list = None, order_by: str = None):
        """筛选多条"""
        query = session.query(cls).filter()
        query = cls.keyword_query(query, q)
        if filter_:
            query = query.filter(*filter_)
        if order_by:
            query = query.order_by(text(order_by))
        return query

    @classmethod
    def delete_items(cls, session, filter_: list, commit=True):
        """批量删除"""
        query = session.query(cls).filter(*filter_)
        count = query.delete()
        if commit:
            session.commit()
        return count

    @classmethod
    def get_page_items(cls,  session, q: str = None, filter_: list = None, page: int = None, page_size: int = None,
                       order_by: str = None):
        """返回http"""
        query = cls.get_items(session=session, q=q, filter_=filter_, order_by=order_by)
        total = query.count()
        if page and page_size:
            query = query.offset((page - 1) * page_size).limit(page_size)
        return {'page': page, 'page_size': page_size, 'total': total, 'data': query.all()}
